package com.ccl.iot.template;
import android.content.Context;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

import com.ccl.iot.monitor.ScreenMonitor;

import java.util.Timer;
import java.util.TimerTask;

public class GraphicView extends SurfaceView implements SurfaceHolder.Callback {
    private final static int KREPAINT_TIMES = 3;
    /*
     * 	Static functions
     */
    private static Timer gTimer = null;
    private static volatile int gTaskCount = 0;

    private static void StopTimer() {
        if (gTimer != null) {
            if (gTaskCount == 0) {
                gTimer.cancel();
                gTimer = null;
            }
        }
    }

    /*
     * 	Non-static functions
     */
    private int iPaintInterval = 10;

    private SurfaceHolder iHolder;
    private volatile boolean iPainting = false;

    private volatile int iRepaint = KREPAINT_TIMES;
    private int iFrameRate = 0;

    public GraphicView(Context context) {
        super(context);

        iHolder = super.getHolder();
        iHolder.addCallback(this);

        super.setFocusable(true);
    }

    public void setPaintInterval(int aInterval) {
        iPaintInterval = aInterval;
    }

    public int getPaintInterval() {
        return iPaintInterval;
    }

    @Override
    public void surfaceCreated(SurfaceHolder aHolder) {
    }

    @Override
    public void surfaceChanged(SurfaceHolder aHolder, int aFormat, int aWidth, int aHeight) {
        invalidate();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder aHolder) {
        onHide();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        onHide();
    }

    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);

        if (visibility == View.VISIBLE && this.getWindowVisibility() == View.VISIBLE && this.isShown()) {
            super.setZOrderMediaOverlay(true);
            onShow();
        } else {
            super.setZOrderMediaOverlay(false);
            onHide();
        }
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);
        if (visibility == View.VISIBLE && this.getVisibility() == View.VISIBLE && this.isShown()) {
            super.setZOrderMediaOverlay(true);
            onShow();
        } else {
            super.setZOrderMediaOverlay(false);
            onHide();
        }
    }

    protected void onPaint(Canvas aCanvas) {

    }

    public int getFrameRate() {
        return iFrameRate;
    }

    private void paint() {
        if (iRepaint > 0 && iPainting && iHolder != null) {
            long tTick = System.currentTimeMillis();
            Canvas tCanvas;

            iRepaint--;

            // TODO java.lang.IllegalStateException: Surface has already been released.
            if ((tCanvas = iHolder.lockCanvas()) != null) {
                onPaint(tCanvas);

                iHolder.unlockCanvasAndPost(tCanvas);

                tTick = System.currentTimeMillis() - tTick;
                iFrameRate = (int) (1000 / (tTick > 0 ? tTick : 1));
            }
        }
    }

    private void repaint() {
        iRepaint = KREPAINT_TIMES;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        paint();
    }

    private void startPaintTask(long aDelay) {
        if (gTimer == null) {
            gTimer = new Timer("Graphic paint thread");
        }

        gTaskCount++;

        gTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                gTaskCount--;

                paint();

                if (iPainting) {
                    startPaintTask(iRepaint == KREPAINT_TIMES ? 1 : iPaintInterval);
                } else {
                    StopTimer();
                }
            }
        }, aDelay);
    }

    private void performShow() {
        if (iPainting == false) {
            iPainting = true;
            repaint();

            startPaintTask(0);
        }
    }

    private void performHide() {
        if (iPainting) {
            iPainting = false;
        }
    }

    private ScreenMonitor.OnScreenChangeListener iScreenChangeListener = new ScreenMonitor.OnScreenChangeListener() {
        @Override
        public void onScreenChange(boolean aOn) {
            if (aOn) {
                if (isShown()) {
                    performShow();
                }
            } else {
                performHide();
            }
        }
    };

    protected void onShow() {
        performShow();

        ScreenMonitor.AddOnScreenChangeListener(iScreenChangeListener);
    }

    protected void onHide() {
        performHide();

        ScreenMonitor.RemoveOnScreenChangeListener(iScreenChangeListener);
    }

    @Override
    public void invalidate() {
        repaint();

        paint();
    }

    @Override
    public void postInvalidate() {
        repaint();
    }
}
